import * as Cesium from 'cesium'

const testVertex = `
  in vec3 position3DHigh;
  in vec3 position3DLow;
  in float batchId;
  in vec4 color;
  in vec3 position;
  in vec2 a_texCoord;
  // 真正的模型坐标系的y轴
  uniform vec3 rotationAxis;
  precision mediump float;
  out vec4 v_color;
  out vec2 v_texCoord;

  // 计算两个向量的点积
  // float dot(vec3 a, vec3 b) {
  //   return a.x * b.x + a.y * b.y + a.z * b.z;
  // }
  
  // // 计算两个向量的叉积
  // vec3 cross(vec3 a, vec3 b) {
  //   return vec3(
  //       a.y * b.z - a.z * b.y,
  //       a.z * b.x - a.x * b.z,
  //       a.x * b.y - a.y * b.x
  //   );
  // }
  
  // // 计算向量的模长
  // float length(vec3 v) {
  //   return sqrt(dot(v, v));
  // }
  
  // // 标准化向量
  // vec3 normalize(vec3 v) {
  //   return v / length(v);
  // }
  
  // 罗德里格旋转公式
  vec3 rodriguesRotate(vec3 v, vec3 k, float theta) {
    vec3 k_hat = normalize(k); // 确保旋转轴是单位向量
    float c = cos(theta);
    float s = sin(theta);
    vec3 oneMinusC = vec3(1.0 - c);

    // 旋转矩阵的组成部分
    vec3 k_cross_v = cross(k_hat, v);
    vec3 k_cross_k_cross_v = cross(k_hat, k_cross_v);

    // 应用罗德里格旋转公式
    return (c * v) + (s * k_cross_v) + (oneMinusC * dot(k_hat, v) * k_hat);
  }

  void main() {
    float PI = 3.1415926535897932384626;
    float time = fract(czm_frameNumber / 60.0);
    // vec4 pos = czm_computePosition();   // 返回当前这个顶点的位置
    v_color = color;
    v_texCoord = a_texCoord;
    // 旋转轴，假设绕y轴旋转，这个y轴不是模型坐标系的y轴，是世界笛卡尔坐标系的y轴，rotationAxis才是模型坐标系的y轴
    // vec3 rotationAxis = vec3(1.0, 0.0, 0.0);
    // 旋转角度
    float rotationAngle = sin(time) * PI * 2.35;
    // 旋转后的顶点坐标
    vec3 rotatedPosition = rodriguesRotate(position, rotationAxis, rotationAngle);
    gl_Position = czm_projection * czm_modelView * vec4(rotatedPosition, 1.0);
  }
`

const testFrag = `
  in vec4 v_color;
  in vec2 v_texCoord;
  precision mediump float;
  uniform float randomNumber;
  uniform sampler2D u_texture;
  out vec4 myFragColor;

  void main() {
    float time = fract(czm_frameNumber / 60.0);
    // gl_FragColor = vec4(1.0, 1.0, 0.0, 1.0);
    // gl_FragColor = v_color;
    // gl_FragColor = vec4(randomNumber, randomNumber * czm_frameNumber, randomNumber, 1.0);
    vec4 color = texture(u_texture, v_texCoord);
    myFragColor = vec4(color.rgb, 0.8);
    // myFragColor = vec4(1.0, 1.0, 0.0, 1.0);
  }
`
export default class PyramidPrimitive {
  constructor() {
    this.drawCommand = null
    this.texture = null
    // 旋转轴
    this.rotationAxis = null
    this._image = null
    this._canvas = this.getColorRamp()
  }
  /**
   * 将经纬度坐标转换为笛卡尔坐标
   * @param {*} i 列索引
   * @param {*} j 航索引
   * @returns [pos.x, pos.y, pos.z]
   */
  transformPos(lonlat, height = 300000.0) {
      let pos = Cesium.Cartesian3.fromDegrees(...lonlat, height)
      return [pos.x, pos.y, pos.z]
  }
  /**
   * 根据坐标中心点生成周围四个点坐标
   * @param {*} v1 
   * @param {*} v2 
   * @returns 
   */
  addVector(v1, v2) {
    return [v1[0] + v2[0], v1[1] + v2[1]]
  }
  /**
   * 根据中心点坐标生成倒锥形坐标、索引和颜色
   * @param {*} center 倒锥形中心点坐标
   * @returns 
   */
  drawPyramid(center) {
    const __GROUND_HEIGHT = 0
    const __BASE_HEIGHT = 300000.0

    const leftTop = this.addVector(center, [-2, 2])
    const rightTop = this.addVector(center, [2, 2])
    const leftBottom = this.addVector(center, [-2, -2])
    const rightBottom = this.addVector(center, [2, -2])
    /**
     * 这里positions数组存放的是笛卡尔坐标系中的顶点坐标，
     * colors数组存放的是顶点颜色，
     * indices数组存放的是三角面片的顶点索引，
     * 其中positions / 3和colors / 4必须相等。
     */
    const positions = []
    positions.push(...this.transformPos(center, __GROUND_HEIGHT),
                   ...this.transformPos(leftTop, __BASE_HEIGHT),
                   ...this.transformPos(rightTop, __BASE_HEIGHT),
                   ...this.transformPos(leftBottom, __BASE_HEIGHT),
                   ...this.transformPos(rightBottom, __BASE_HEIGHT))

    const indices = [
      0, 1, 3,
      0, 1, 2,
      0, 2, 4,
      0, 3, 4,
      1, 2, 3,
      2, 3, 4
    ]
    const colors = new Array(positions.length * 4 / 3).fill(Math.random())
    const uv = [
      0.5, 0.5, 
      0.0, 1.0, 
      1.0, 1.0, 
      0.0, 0.0, 
      1.0, 0.0
    ]
    // 定义旋转轴
    this.rotationAxis = new Cesium.Cartesian3(...this.transformPos(center, __GROUND_HEIGHT))
    return [ positions, colors, indices, uv ]
  }
  /**
   * 根据自定义Geometry生成Primitive对象
   * @returns {Cesium.Primitive}
   */
  generatePyramidGeometry() {
    const center = [114.25, 40.59]
    const [positions, colors, indices, uv] = this.drawPyramid(center)
    // 添加平移分量
    const translate = new Cesium.Cartesian3(0, 0, 10000)
    const matrixWithTranslate = Cesium.Matrix4.fromTranslation(translate, new Cesium.Matrix4())
    console.log('平移矩阵', matrixWithTranslate)
  
    const geometry = new Cesium.Geometry({
      attributes: {
        position: new Cesium.GeometryAttribute({
          /**
           * DOUBLE表示64位双精度浮点数，FLOAT表示32位单精度浮点数。
           * DOUBLE通常用于需要高精度的顶点坐标数据，如位置（position）属性。
           * 使用Cesium.ComponentDatatype.DOUBLE时，顶点数据的值必须传递为Float64Array类型。
           * 而使用Cesium.ComponentDatatype.FLOAT时，则必须传递为Float32Array类型。
           */
          componentDatatype: Cesium.ComponentDatatype.DOUBLE,
          componentsPerAttribute: 3,
          values: new Float64Array(positions)
        }),
        color: new Cesium.GeometryAttribute({
          componentDatatype: Cesium.ComponentDatatype.FLOAT,
          componentsPerAttribute: 4,
          values: new Float32Array(colors)
        }),
        a_texCoord: new Cesium.GeometryAttribute({
          componentDatatype: Cesium.ComponentDatatype.FLOAT,
          componentsPerAttribute: 2,
          values: new Float32Array(uv)
        })
      },
      primitiveType: Cesium.PrimitiveType.TRIANGLES,
      indices: indices,
      boundingSphere: Cesium.BoundingSphere.fromVertices(positions)
    })
    /**
     * 创建将属性名称映射到唯一位置（索引）的对象 用于匹配顶点属性和着色器程序。
     * { position: 0, color: 1, a_texCoord: 2 }
     */
    console.log('pyramid-pipeline', Cesium.GeometryPipeline.createAttributeLocations(geometry))
    return geometry
  }
  /**
   * 创建DrawCommand对象，用于渲染Primitive对象。
   * @param {*} context 
   */
  createDrawCommand(context) {
    let geometry = this.  generatePyramidGeometry()
    let vertexArray = Cesium.VertexArray.fromGeometry({
      context: context,
      geometry: geometry,
      attributeLocations: Cesium.GeometryPipeline.createAttributeLocations(geometry)
    })
    let shaderProgram = Cesium.ShaderProgram.fromCache({
      context: context,
      vertexShaderSource: testVertex,
      fragmentShaderSource: testFrag,
      attributeLocations: Cesium.GeometryPipeline.createAttributeLocations(geometry)
    })
    let uniformMap = {
      randomNumber() {
        return Math.random()
      },
      rotationAxis: () => {
        return this.rotationAxis
      },
      u_texture: () => {
        if(this.texture === null) {
          return context.defaultTexture
        }
        return this.texture
      }
    }
    let renderState = Cesium.RenderState.fromCache({
      depthTest: {
        enabled: true,
      },
      depthMask: false,
      blending: Cesium.BlendingState.ALPHA_BLEND,
    })
    const translate = new Cesium.Cartesian3(0, 0, 20000)
    
    this.drawCommand = new Cesium.DrawCommand({
      vertexArray: vertexArray,
      shaderProgram: shaderProgram,
      renderState: renderState,
      uniformMap: uniformMap,
      pass: Cesium.Pass.OPAQUE,
      castShadows: false,
      receiveShadows: false,
      primitiveType: Cesium.PrimitiveType.TRIANGLES,
      // 设置模型的位置，这个是固定位置
      modelMatrix: Cesium.Matrix4.fromTranslation(translate)
    })
  }
  /**
   * 颜色过渡方案
   * @returns canvas对象
   */
  getColorRamp() {
    const ramp = document.createElement('canvas')
    ramp.width = 1
    ramp.height = 100
    const ctx = ramp.getContext('2d')
    const grd = ctx.createLinearGradient(0, 0, 0, 100)
    grd.addColorStop(1, '#0000ff')
    grd.addColorStop(0.5, '#00ff00')
    grd.addColorStop(0.75, '#ffff00')
    grd.addColorStop(1.0, '#ff0000')
    ctx.fillStyle = grd
    ctx.fillRect(0, 0, 1, 100)
    return ramp
  }
  /**
   * 创建纹理
   * @param {*} context 
   */
  createTexture(context) {
    if(this._image === null) {
      this._image = new Image()
      this._image.src = '五角星.png'
      this._image.onload = () => {
        this.texture = new Cesium.Texture({
          context: context,
          source: this._canvas
        })
        console.log('texture', this.texture)
      }
    }
  }
  /**
   * 更新Primitive对象，将其添加到渲染队列中。
   * @param {*} framestate 
   */
  update(framestate) {
    
    if(this.drawCommand === null) {
      this.createDrawCommand(framestate.context)
      console.log(framestate.context)
    }
    if(this.texture === null) {
      this.createTexture(framestate.context)
    }
    framestate.commandList.push(this.drawCommand)
  }
}
